const User = require('mongoose').model('User');
const Article = require('mongoose').model('Article');
const Relationship = require('mongoose').model('Relationship');
const  mongoose = require('mongoose');
const crypto = require('crypto');
const passport = require('passport');

function getErrorMessage(err) {
    let message = '';
    //It is worth noticing that there are two
    //possible errors here: a MongoDB indexing error handled using the error code,
    //and a Mongoose validation error handled using the err.errors object
    if (err.code) {
        switch (err.code) {
            case 11000:
            case 11001:
                message = 'Username already exists';
                break;
            default:
                message = 'Something went wrong';
        }
    } else {
        for (let errName of err.errors) {
            if (err.errors[errName].message) message =
                err.errors[errName].message;
        }
    }
    return message;
};

 function showFollowingCount(req, res) {
    User.aggregate(
        {'$match': {'_id': mongoose.Types.ObjectId(req.params.userId)}},
        {'$project': {'followingCount': 1}},
        function (err, back) {
            if(err) return getErrorMessage(err);
            res.status(200).json(back);
        }
    )
};

 function addFollowing(req, res) {
     User.update({'_id': mongoose.Types.ObjectId(req.params.userId)},
         {'$inc': {'followingCount': 1}},
         function (err) {
             if(err) return getErrorMessage(err);
             req.user.followersCount += 1;
             req.user.followers.push(mongoose.Types.ObjectId(req.params.userId));
             req.user.save((err)=>{
                 if(err) return getErrorMessage(err);
                 Relationship.create({'userId': mongoose.Types.ObjectId(req.params.userId),
                     'following': req.user._id},function (err) {
                     if(err) return getErrorMessage(err);
                     showFollowingCount(req, res);
                 });
             });
         });
 }

 function remFollowing(req, res) {
     User.update({'_id': mongoose.Types.ObjectId(req.params.userId)},
         {'$inc': {'followingCount': -1}},
         function (err) {
             if(err) return getErrorMessage(err);
             req.user.followersCount -= 1;
             var num = req.user.followers.indexOf(mongoose.Types.ObjectId(req.params.userId));
             if(num > -1) req.user.followers.splice(num, 1);
             req.user.save((err)=>{
                 if(err) return getErrorMessage(err);
                 Relationship.remove({'userId': mongoose.Types.ObjectId(req.params.userId),
                     'following': req.user._id},function (err) {
                     if(err) getErrorMessage(err);
                     showFollowingCount(req, res);
                 });
             })
         });
 }

exports.Signup = function(req, res) {
    const user = new User(req.body);
    user.salt = Buffer.from(crypto.randomBytes(16).toString('base64'), 'base64');
    user.password = user.hashPassword(user.password);
    user.save((err) => {
        if (err) {
            return res.status(400).send({
                message: getErrorMessage(err)
            });
        } else {
            // Remove sensitive data before login
            user.password = undefined;
            user.salt = undefined;
            req.login(user, function(err) {
                if (err) {
                    res.status(400).send(err);
                } else {
                    res.json(user);
                }
            });
        }
    });
};

exports.Signin = function (req, res, next) {
    passport.authenticate('local', function (err, user, info) {
        if(err || !user) {
            res.status(400).send(info);
        }else {
            //remove sensitive data before login
            user.password = undefined;
            user.salt = undefined;
            req.login(user, function (err) {
                if(err) {
                    res.status(400).send(err);
                }else{
                    res.json(user);
                }
            });
        }
    })(req, res, next);
};

exports.Signout = function(req, res) {
    req.logout();
    res.redirect('/');
};

exports.Introduce= function (req, res) {
    var userInfo;
    var articleInfo;
   Article.aggregate(
       {'$match': {'creator': mongoose.Types.ObjectId(req.params.userId)}},
       {'$project': {'title': 1, 'content': 1}},
       function (err, articleInfo) {
           if(err) return getErrorMessage(err);
           User.aggregate(
               {'$match': {'_id': mongoose.Types.ObjectId(req.params.userId)}},
               {'$project': {'username': 1, 'email': 1, 'followingCount':1, 'followersCount': 1}},
               function (err, userInfo) {
                   if(err) return getErrorMessage(err);
                   res.status(200).json(userInfo.concat(articleInfo));
               }
           );
       });
};

exports.Toggle_like = function (req, res) {
    Relationship.find({'userId': mongoose.Types.ObjectId(req.params.userId),
        'following': req.user._id},function (err, docs) {
        if(err) getErrorMessage(err);
        if(docs.length == 0) {
            addFollowing(req, res);
        }else{
            remFollowing(req, res);
        }
    })
};

exports.Lover = function (req, res) {
    User.find({'_id': req.params.userId}, 'followers').populate(
        'followers', 'username _id followingCount followersCount'
    ).exec((err, follower)=> {
        if(err) return getErrorMessage(err);
        res.status(200).json(follower)
    })
};

exports.Fan = function (req, res) {
    Relationship.find({'userId': mongoose.Types.ObjectId(req.params.userId)},
        'following -_id').populate(
        'following', 'username _id followingCount followersCount'
    ).exec((err, following)=> {
        if(err) return getErrorMessage(err)
        res.status(200).json(following);
    })
}

exports.requiresLogin = function (req, res, next) {
    if(!req.isAuthenticated()) {
        return res.status(401).send({
            message: 'User is not logged in'
        });
    }
    next();
};
